﻿#include<iostream>
#include<cstring>
#include"../Concurrency/TimeStamp.hpp"
#include"Buffer.hpp"


namespace MMFLogger{


    Buffer::Buffer(uint32_t capacity, size_t interval)
        : mCapacity(capacity)
        , mFileInterval(interval)
        , mWriteSize(0)
        , mReadSize(0)
        , mIsQuit(false)
        , mLastTime(0)
        , mWorker(nullptr)
    {
        mMem = new char[capacity]{};
        mAssistMem = new char[capacity + 1]{};
        CreateFile();
        CreateWorker();
    }

    Buffer::~Buffer()
    {
        //通知线程退出
        mIsQuit = true;
        mWriteSize.notify_all();
        mReadSize.notify_all();

        //等待释放worker
        if (mWorker && mWorker->joinable())
        {
            mWorker->join();
            delete mWorker;
            mWorker = nullptr;
        }

        //文件数据落盘
        mFile.flush();

        //释放内存
        delete[] mMem;
        mMem = nullptr;
        delete[] mAssistMem;
        mAssistMem = nullptr;
    }

    void Buffer::CreateFile()
    {
        //获取当前时间
        char buff[512] = {};
        time_t t = time(NULL);
        tm* pt = localtime(&t);
        
        //将时间转化为字符串
        std::string path = std::filesystem::current_path().string() + "/%d%d%d_%d%d%d.log";
        sprintf(
            buff, path.data(),
            pt->tm_year + 1900,
            pt->tm_mon + 1,
            pt->tm_mday,
            pt->tm_hour,
            pt->tm_min,
            pt->tm_sec
        );

        if (mFile.is_open())
        {
            mFile.flush();
            mFile.close();
        }

        mFile.open(buff, std::ios::binary);

        mLastTime = MMF::TimeStamp::GetUsTime().count();
    }

     void Buffer::Reset()
     {
        mMutex.Lock();
        mWriteSize = 0;
        mMutex.Unlock();
        mReadSize = 0;
     }

    uint32_t Buffer::Write(const char* mem, uint32_t size)
    {
        //获取能写入的数量，并将已经写入过的数量增加
        mMutex.Lock();

        uint32_t needWrite = 0;
        uint32_t curWriteSize = mWriteSize.load();

        if (curWriteSize + size <= mCapacity)
            needWrite = size;
        else 
            needWrite = size - ((curWriteSize + size) - mCapacity);

        mWriteSize += needWrite;

        mMutex.Unlock();

        //拷贝数据
        memcpy(mMem + curWriteSize, mem, needWrite);

        //通知数据已经拷贝完成
        mWriteSize.notify_one();

        return needWrite;
    }

    bool Buffer::IsFull()
    {
        return mWriteSize == mCapacity;
    }

    void Buffer::CreateWorker()
    {
        //定时器线程
        mTimer = new std::thread([this](){
            while(!mIsQuit)
            {
                std::this_thread::sleep_for(std::chrono::milliseconds(10));   //10毫秒一次
                mWriteSize.notify_one();
            }
        }); 

        //工作线程
        mWorker = new std::thread([this](){
            while(!mIsQuit)
            {
                mMutex.Lock();
                uint32_t old = mWriteSize.load();
                mMutex.Unlock();

                if (mWriteSize != mReadSize)
                {
                    uint32_t readSize = mReadSize.load();
                    memcpy(mAssistMem, mMem + readSize, old - readSize);

                    //添加了1个字节的控制字符, 用于在控制台上显示的时候结束字符串
                    mAssistMem[old - readSize] = '\0';

                    //写在控制台
                    std::cout << mAssistMem;

                    //写入文件数据
                    mFile.write(mAssistMem, old - readSize);

                    //增加已经读取的数量
                    mReadSize += (old - readSize);

                    //buffer已经用满，并且数据已经写入完成
                    if (old == mCapacity && mReadSize.load() == old)
                        Reset();
                }
                else 
                {
                    //如果没有更多数据就休眠
                    mWriteSize.wait(old);
                }

                //判断是否需要创建新文件
                size_t curTime = MMF::TimeStamp::GetUsTime().count();
                if (curTime - mLastTime >= mFileInterval)       //按一定的时间间隔创建日志记录文件
                {
                    mLastTime = curTime;
                    CreateFile();
                }
            }

            //释放定时器
            if (mTimer && mTimer->joinable())
            {
                mTimer->join();
                delete mTimer;
                mTimer = nullptr;
            }
        });
    }
}